package com.firefly.admin.common.annotations.aspect;

import com.alibaba.fastjson.JSON;
import com.firefly.admin.common.annotations.annotation.LoginLog;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import com.firefly.admin.common.constant.Constants;
import com.firefly.admin.common.service.CommonService;
import com.firefly.admin.common.utils.JwtTokenUtil;
import com.firefly.admin.common.utils.LogUtil;
import com.firefly.admin.common.utils.RedisUtil;
import com.firefly.admin.common.vo.LoginUser;
import com.firefly.admin.common.vo.Result;
import com.firefly.admin.login.vo.LoginInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AuthorizationServiceException;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

@Component
@Aspect
public class LoginLogAspect {
    @Autowired
    private CommonService commonService;

    /**
     * 设置操作日志的切入点，用来记录操作日志，在标明注解的位置切入
     */
    @Pointcut("@annotation(com.firefly.admin.common.annotations.annotation.LoginLog)")
    public void loginLogPointCut() {

    }

    /**
     * 设置操作异常切入点，拦截用户的登录日志，连接点正常执行后执行，若连接点抛出异常则不会执行
     *
     * @param joinPoint 切入点
     * @param keys      返回结果
     */
    @AfterReturning(value = "loginLogPointCut()", returning = "keys")
    public void saveLoginLog(JoinPoint joinPoint, Object keys) {
        try {
            //在切面织入点通过反射机制获取织入点的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            //获取织入点的方法
            Method method = signature.getMethod();
            //获取操作
            LoginLog loginLog = method.getAnnotation(LoginLog.class);
            String operateType = loginLog.operateType();
            if (Constants.LoginOperateType.LOGIN.equals(operateType)) {
                saveLog(joinPoint, operateType, keys);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置操作异常切入点，拦截用户的登录日志，连接点正常执行后执行，若连接点抛出异常则不会执行
     *
     * @param joinPoint 切入点
     */
    @Before("loginLogPointCut()")
    public void beforeSaveLoginLog(JoinPoint joinPoint) {
        try {
            //在切面织入点通过反射机制获取织入点的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            //获取织入点的方法
            Method method = signature.getMethod();
            //获取操作
            LoginLog loginLog = method.getAnnotation(LoginLog.class);
            String operateType = loginLog.operateType();
            if (Constants.LoginOperateType.LOGOUT.equals(operateType)) {
                saveLog(joinPoint, operateType, null);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void saveLog(JoinPoint joinPoint, String operateType, Object keys) {
        HttpServletRequest request = commonService.getRequest();
        //在切面织入点通过反射机制获取织入点的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取织入点的方法
        Method method = signature.getMethod();
        //获取请求的类名
        String className = joinPoint.getTarget().getClass().getName();
        //获取请求的方法
        String methodName = method.getName();
        methodName = className + "." + methodName;
        String responseResult = "";
        String operateResult = "";
        String operatorName = "";
        String requestParam = "";
        if (Constants.LoginOperateType.LOGIN.equals(operateType)) {
            responseResult = JSON.toJSONString(keys);
            Result result = (Result) keys;
            Integer code = result.getCode();
            if (code == 200) {
                operateResult = Constants.OperateResult.SUCCESS;
            } else {
                operateResult = Constants.OperateResult.FAIL;
            }
            Object[] paramValues = joinPoint.getArgs();
            LoginInfoVo loginInfoVo = (LoginInfoVo) paramValues[0];
            operatorName = loginInfoVo.getUserName();
            //将参数所在的数组转为json
            requestParam = JSON.toJSONString(loginInfoVo);
        } else {
            operateResult = Constants.OperateResult.SUCCESS;
            operatorName = getUserName();
        }
        LogUtil.saveLoginOrLogoutLog(request, methodName, operateType, operateResult, responseResult, requestParam, operatorName);
    }

    public String getUserName() {
        HttpServletRequest request = commonService.getRequest();
        String authorization = request.getHeader("Authorization");
        if (StringUtils.isNotEmpty(authorization)) {
            String userKey = JwtTokenUtil.getUserKey(authorization.substring(6));
            LoginUser loginUser = (LoginUser) RedisUtil.get(userKey);
            if (loginUser != null) {
                return loginUser.getFySystemUser().getUserName();
            } else {
                return "系统自动登出";
            }
        }
        throw new AuthorizationServiceException("未授权");
    }
}
